Advertisement
Guest User

Untitled

a guest
Dec 12th, 2009
538
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. Ext.namespace('Ext.ux.maximgb.treegrid');
  2.  
  3. /**
  4.  * This class shouldn't be created directly use NestedSetStore or AdjacencyListStore instead.
  5.  *
  6.  * @abstract
  7.  */
  8. Ext.ux.maximgb.treegrid.AbstractTreeStore = Ext.extend(Ext.data.Store, {
  9.     /**
  10.      * @cfg {String} is_leaf_field_name Record leaf flag field name.
  11.      */
  12.     leaf_field_name: '_is_leaf',
  13.    
  14.     /**
  15.      * Current page offset.
  16.      *
  17.      * @access private
  18.      */
  19.     page_offset: 0,
  20.    
  21.     /**
  22.      * Current active node.
  23.      *
  24.      * @access private
  25.      */
  26.     active_node: null,
  27.    
  28.     /**
  29.      * @constructor
  30.      */
  31.     constructor: function(config) {
  32.        
  33.         Ext.ux.maximgb.treegrid.AbstractTreeStore.superclass.constructor.call(this, config);
  34.        
  35.         if (!this.paramNames.active_node) {
  36.             this.paramNames.active_node = 'anode';
  37.         }
  38.        
  39.         this.addEvents(    
  40.         /**
  41.          * @event beforeexpandnode
  42.          * Fires before node expand. Return false to cancel operation.
  43.          * param {AbstractTreeStore} this
  44.          * param {Record} record
  45.          */
  46.         'beforeexpandnode',  
  47.         /**
  48.          * @event expandnode
  49.          * Fires after node expand.
  50.          * param {AbstractTreeStore} this
  51.          * param {Record} record
  52.          */
  53.         'expandnode',
  54.         /**
  55.          * @event expandnodefailed
  56.          * Fires when expand node operation is failed.
  57.          * param {AbstractTreeStore} this
  58.          * param {id} Record id
  59.          * param {Record} Record, may be undefined
  60.          */
  61.         'expandnodefailed',  
  62.         /**
  63.          * @event beforecollapsenode
  64.          * Fires before node collapse. Return false to cancel operation.
  65.          * param {AbstractTreeStore} this
  66.          * param {Record} record
  67.          */
  68.         'beforecollapsenode',  
  69.         /**
  70.          * @event collapsenode
  71.          * Fires after node collapse.
  72.          * param {AbstractTreeStore} this
  73.          * param {Record} record
  74.          */
  75.         'collapsenode',  
  76.         /**
  77.          * @event beforeactivenodechange
  78.          * Fires before active node change. Return false to cancel operation.
  79.          * param {AbstractTreeStore} this
  80.          * param {Record} old active node record
  81.          * param {Record} new active node record
  82.          */
  83.         'beforeactivenodechange',  
  84.         /**
  85.          * @event activenodechange
  86.          * Fires after active node change.
  87.          * param {AbstractTreeStore} this
  88.          * param {Record} old active node record
  89.          * param {Record} new active node record
  90.          */
  91.         'activenodechange');
  92.     },
  93.    
  94.     // Store methods.
  95.     // ----------------------------------------------------------------------------------------------- 
  96.     /**
  97.      * Removes record and all its descendants.
  98.      *
  99.      * @access public
  100.      * @param {Record} record Record to remove.
  101.      */
  102.     remove: function(record){
  103.  
  104.         if (record === this.active_node) {
  105.             this.setActiveNode(null); }
  106.            
  107.         this.removeNodeDescendants(record);
  108.        
  109.         Ext.ux.maximgb.treegrid.AbstractTreeStore.superclass.remove.call(this, record);
  110.     },
  111.    
  112.     /**
  113.      * Removes node descendants.
  114.      *
  115.      * @access private
  116.      */
  117.     removeNodeDescendants: function(rc){
  118.        
  119.         var i, len, children = this.getNodeChildren(rc);
  120.        
  121.         for (i = 0, len = children.length; i < len; i++) {
  122.             this.remove(children[i]); }
  123.            
  124.     },
  125.    
  126.     /**
  127.      * Applyes current sort method.
  128.      *
  129.      * @access private
  130.      */
  131.     applySort: function(){
  132.  
  133.         if (this.sortInfo && !this.remoteSort) {
  134.            
  135.             var s = this.sortInfo, f = s.field;
  136.             this.sortData(f, s.direction);
  137.            
  138.         } else {
  139.            
  140.             this.applyTreeSort();
  141.            
  142.         }   // if
  143.  
  144.     },
  145.    
  146.     /**
  147.      * Sorts data according to sort params and then applyes tree sorting.
  148.      *
  149.      * @access private
  150.      */
  151.     sortData: function(f, direction){
  152.        
  153.         direction = direction || 'ASC';
  154.        
  155.         var st = this.fields.get(f).sortType;
  156.        
  157.         var fn = function(r1, r2) {
  158.             var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
  159.             return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
  160.         };
  161.        
  162.         this.data.sort(direction, fn);
  163.  
  164.         if (this.snapshot && this.snapshot != this.data) {
  165.             this.snapshot.sort(direction, fn); }
  166.  
  167.         this.applyTreeSort();
  168.  
  169.     },
  170.    
  171.     /**
  172.      * Loads current active record data.
  173.      */
  174.     load: function(options){
  175.    
  176.         if (options) {
  177.            
  178.             if (options.params) {
  179.                
  180.                 if (options.params[this.paramNames.active_node] === undefined) {
  181.                     options.params[this.paramNames.active_node] = this.active_node ? this.active_node.id : null; }
  182.                    
  183.             } else {
  184.                
  185.                 options.params = {};
  186.                 options.params[this.paramNames.active_node] = this.active_node ? this.active_node.id : null;
  187.                
  188.             }   // if
  189.            
  190.         } else {
  191.            
  192.             options = {
  193.                 params: {}
  194.             };
  195.            
  196.             options.params[this.paramNames.active_node] = this.active_node ? this.active_node.id : null;
  197.            
  198.         }   // if
  199.        
  200.         if (options.params[this.paramNames.active_node] !== null) {
  201.             options.add = true; }
  202.        
  203.         return Ext.ux.maximgb.treegrid.AbstractTreeStore.superclass.load.call(this, options);
  204.        
  205.     },
  206.    
  207.     /**
  208.      * Allow to pass options
  209.      */
  210.     loadData : function(o, append, opt){
  211.        
  212.         var r = this.reader.readRecords(o);
  213.         var opt = opt || {};
  214.         opt.add = append;
  215.        
  216.         this.loadRecords(r, opt, true);
  217.        
  218.     },
  219.    
  220.     /**
  221.      * Called as a callback by the Reader during load operation.
  222.      *
  223.      * @access private
  224.      */
  225.     loadRecords: function(o, options, success){
  226.        
  227.         if (!o || success === false) {
  228.            
  229.             if (success !== false) {
  230.                 this.fireEvent("load", this, [], options); }
  231.                
  232.             if (options.callback) {
  233.                 options.callback.call(options.scope || this, [], options, false); }
  234.                
  235.             return;
  236.            
  237.         }
  238.        
  239.         var r = o.records,
  240.             t = o.totalRecords || r.length,
  241.             page_offset = this.getPageOffsetFromOptions(options),
  242.             loaded_node_id = this.getLoadedNodeIdFromOptions(options),
  243.             loaded_node,
  244.             i,
  245.             len,
  246.             self = this
  247.         ;
  248.        
  249.         if (!options || options.add !== true || loaded_node_id === null) {
  250.            
  251.             if (this.pruneModifiedRecords) {
  252.                 this.modified = []; }
  253.            
  254.             for (var i = 0, len = r.length; i < len; i++) {
  255.                 r[i].join(this); }
  256.            
  257.             if (this.snapshot) {
  258.                
  259.                 this.data = this.snapshot;
  260.                 delete this.snapshot;
  261.                
  262.             }
  263.  
  264.             this.data.clear();
  265.             this.data.addAll(r);
  266.             this.page_offset = page_offset;
  267.             this.totalLength = t;
  268.            
  269.             if( options.applySort == undefined ) {
  270.                 options.applySort = true; }
  271.            
  272.             if( options.applySort ) {
  273.                 this.applySort(); }
  274.  
  275.             this.fireEvent("datachanged", this);
  276.  
  277.            
  278.         } else {
  279.  
  280.             loaded_node = this.getById(loaded_node_id);
  281.            
  282.             if (loaded_node) {
  283.            
  284.                 this.setNodeChildrenOffset(loaded_node, page_offset);
  285.                 this.setNodeChildrenTotalCount(loaded_node, Math.max(t, r.length));
  286.                
  287.                 this.removeNodeDescendants(loaded_node);
  288.                 this.suspendEvents();
  289.                
  290.                 for (i = 0, len = r.length; i < len; i++) {
  291.                     this.add(r[i]);
  292.                 }
  293.                
  294.                 if( options.applySort == undefined ) {
  295.                     options.applySort = true; }
  296.                
  297.                 if( options.applySort ) {
  298.                     this.applySort(); }
  299.                
  300.                 this.resumeEvents();
  301.                
  302.                 idx = [];
  303.                
  304.                 r.sort( function(r1, r2) {
  305.                    
  306.                     return (self.data.indexOf(r1) > self.data.indexOf(r2) ) ? 1 : -1;
  307.                    
  308.                 });
  309.                
  310.                 this.suspendEvents();
  311.                
  312.                 for (i = 0, len = r.length; i < len; i++) {
  313.                     this.fireEvent("add", this, [r[i]], this.data.indexOf(r[i])); }
  314.                
  315.                 this.resumeEvents();
  316.                 this.fireEvent("datachanged", this);
  317.                
  318.             }
  319.            
  320.         }
  321.        
  322.         this.fireEvent("load", this, r, options);
  323.        
  324.         if (options.callback) {
  325.             options.callback.call(options.scope || this, r, options, true); }
  326.        
  327.     },
  328.    
  329.     // Tree support methods.
  330.     // -----------------------------------------------------------------------------------------------
  331.    
  332.     /**
  333.      * Sorts store data with respect to nodes parent-child relation. Every child node will be
  334.      * positioned after its parent.
  335.      *
  336.      * @access public
  337.      */
  338.     applyTreeSort: function() {
  339.        
  340.         var i, len, temp, rec, records = [], roots = this.getRootNodes();
  341.        
  342.         // Sorting data
  343.         for (i = 0, len = roots.length; i < len; i++) {
  344.             rec = roots[i];
  345.             records.push(rec);
  346.             this.collectNodeChildrenTreeSorted(records, rec);
  347.         }
  348.        
  349.         if (records.length > 0) {
  350.             this.data.clear();
  351.             this.data.addAll(records);
  352.         }
  353.        
  354.         // Sorting the snapshot if one present.
  355.         if (this.snapshot && this.snapshot !== this.data) {
  356.             temp = this.data;
  357.             this.data = this.snapshot;
  358.             this.snapshot = null;
  359.             this.applyTreeSort();
  360.             this.snapshot = this.data;
  361.             this.data = temp;
  362.         }
  363.        
  364.     },
  365.    
  366.     /**
  367.      * Recusively collects rec descendants and adds them to records[] array.
  368.      *
  369.      * @access private
  370.      * @param {Record[]} records
  371.      * @param {Record} rec
  372.      */
  373.     collectNodeChildrenTreeSorted: function(records, rec) {
  374.  
  375.         var i, len, child, children = this.getNodeChildren(rec);
  376.  
  377.         for (i = 0, len = children.length; i < len; i++) {
  378.             child = children[i];
  379.             records.push(child);
  380.             this.collectNodeChildrenTreeSorted(records, child);
  381.         }
  382.        
  383.     },
  384.    
  385.     /**
  386.      * Returns current active node.
  387.      *
  388.      * @access public
  389.      * @return {Record}
  390.      */
  391.     getActiveNode: function(){
  392.        
  393.         return this.active_node;
  394.        
  395.     },
  396.    
  397.     /**
  398.      * Sets active node.
  399.      *
  400.      * @access public
  401.      * @param {Record} rc Record to set active.
  402.      */
  403.     setActiveNode: function(rc){
  404.        
  405.         if (this.active_node !== rc) {
  406.            
  407.             if (rc) {
  408.                
  409.                 if (this.data.indexOf(rc) != -1) {
  410.                    
  411.                     if (this.fireEvent('beforeactivenodechange', this, this.active_node, rc) !== false) {
  412.                        
  413.                         this.active_node = rc;
  414.                         this.fireEvent('activenodechange', this, this.active_node, rc);
  415.                        
  416.                     }   // if
  417.                    
  418.                 } else {
  419.                    
  420.                     throw "Given record is not from the store.";
  421.                    
  422.                 }   // if
  423.                
  424.             } else {
  425.                
  426.                 if (this.fireEvent('beforeactivenodechange', this, this.active_node, rc) !== false) {
  427.                    
  428.                     this.active_node = rc;
  429.                     this.fireEvent('activenodechange', this, this.active_node, rc);
  430.                    
  431.                 }   // if
  432.                
  433.             }   // if
  434.        
  435.         }   // if
  436.        
  437.        
  438.     },
  439.    
  440.     /**
  441.      * Returns true if node is expanded.
  442.      *
  443.      * @access public
  444.      * @param {Record} rc
  445.      */
  446.     isExpandedNode: function(rc){
  447.        
  448.         return rc.ux_maximgb_treegrid_expanded === true;
  449.        
  450.     },
  451.    
  452.     /**
  453.      * Sets node expanded flag.
  454.      *
  455.      * @access private
  456.      */
  457.     setNodeExpanded: function(rc, value){
  458.        
  459.         rc.ux_maximgb_treegrid_expanded = value;
  460.        
  461.     },
  462.    
  463.     /**
  464.      * Returns true if node's ancestors are all expanded - node is visible.
  465.      *
  466.      * @access public
  467.      * @param {Record} rc
  468.      */
  469.     isVisibleNode: function(rc){
  470.        
  471.         var i, len, ancestors = this.getNodeAncestors(rc), result = true;
  472.        
  473.         for (i = 0, len = ancestors.length; i < len; i++) {
  474.            
  475.             result = result && this.isExpandedNode(ancestors[i]);
  476.            
  477.             if (!result) {
  478.                 break; }
  479.            
  480.         }
  481.        
  482.         return result;
  483.     },
  484.    
  485.     /**
  486.      * Returns true if node is a leaf.
  487.      *
  488.      * @access public
  489.      * @return {Boolean}
  490.      */
  491.     isLeafNode: function(rc){
  492.        
  493.         return rc.data[this.leaf_field_name] == true;
  494.        
  495.     },
  496.    
  497.     /**
  498.      * Returns true if node was loaded.
  499.      *
  500.      * @access public
  501.      * @return {Boolean}
  502.      */
  503.     isLoadedNode: function(rc) {
  504.  
  505.         var result;
  506.        
  507.         if (rc.ux_maximgb_treegrid_loaded !== undefined) {
  508.            
  509.             result = rc.ux_maximgb_treegrid_loaded
  510.            
  511.         } else if (this.isLeafNode(rc) || this.hasChildNodes(rc)) {
  512.            
  513.             result = true;
  514.            
  515.         } else {
  516.            
  517.             result = false;
  518.            
  519.         }   // if
  520.        
  521.         return result;
  522.        
  523.     },
  524.    
  525.     /**
  526.      * Sets node loaded state.
  527.      *
  528.      * @access private
  529.      * @param {Record} rc
  530.      * @param {Boolean} value
  531.      */
  532.     setNodeLoaded: function(rc, value) {
  533.        
  534.         rc.ux_maximgb_treegrid_loaded = value;
  535.        
  536.     },
  537.    
  538.     /**
  539.      * Returns node's children offset.
  540.      *
  541.      * @access public
  542.      * @param {Record} rc
  543.      * @return {Integer}
  544.      */
  545.     getNodeChildrenOffset: function(rc) {
  546.        
  547.         return rc.ux_maximgb_treegrid_offset || 0;
  548.        
  549.     },
  550.    
  551.     /**
  552.      * Sets node's children offset.
  553.      *
  554.      * @access private
  555.      * @param {Record} rc
  556.      * @parma {Integer} value
  557.      */
  558.     setNodeChildrenOffset: function(rc, value){
  559.        
  560.         rc.ux_maximgb_treegrid_offset = value;
  561.        
  562.     },
  563.    
  564.     /**
  565.      * Returns node's children total count
  566.      *
  567.      * @access public
  568.      * @param {Record} rc
  569.      * @return {Integer}
  570.      */
  571.     getNodeChildrenTotalCount: function(rc){
  572.        
  573.         return rc.ux_maximgb_treegrid_total || 0;
  574.        
  575.     },
  576.    
  577.     /**
  578.      * Sets node's children total count.
  579.      *
  580.      * @access private
  581.      * @param {Record} rc
  582.      * @param {Integer} value
  583.      */
  584.     setNodeChildrenTotalCount: function(rc, value){
  585.        
  586.         rc.ux_maximgb_treegrid_total = value;
  587.        
  588.     },
  589.    
  590.     /**
  591.      * Collapses node.
  592.      *
  593.      * @access public
  594.      * @param {Record} rc
  595.      * @param {Record} rc Node to collapse.
  596.      */
  597.     collapseNode: function(rc){
  598.        
  599.         if(
  600.             this.isExpandedNode(rc) &&
  601.             this.fireEvent('beforecollapsenode', this, rc) !== false
  602.         ) {
  603.            
  604.             this.setNodeExpanded(rc, false);
  605.             this.fireEvent('collapsenode', this, rc);
  606.            
  607.         }   // if
  608.     },
  609.    
  610.     /**
  611.      * Expands node.
  612.      *
  613.      * @access public
  614.      * @param {Record} rc
  615.      */
  616.     expandNode: function(rc){
  617.        
  618.         var params;
  619.        
  620.         if (
  621.             !this.isExpandedNode(rc) &&
  622.             this.fireEvent('beforeexpandnode', this, rc) !== false
  623.         ) {
  624.            
  625.             // If node is already loaded then expanding now.
  626.             if (this.isLoadedNode(rc)) {
  627.  
  628.                 this.setNodeExpanded(rc, true);
  629.                 this.fireEvent('expandnode', this, rc);
  630.                
  631.             } else {
  632.                
  633.                 // If node isn't loaded yet then expanding after load.
  634.                
  635.                 params = {};
  636.                 params[this.paramNames.active_node] = rc.id;
  637.                
  638.                 this.load({
  639.                     add: true,
  640.                     params: params,
  641.                     callback: this.expandNodeCallback,
  642.                     scope: this
  643.                 });
  644.                
  645.             }   // if
  646.                    
  647.         }   // if
  648.        
  649.     },
  650.    
  651.     /**
  652.      * @access private
  653.      */
  654.     expandNodeCallback: function(r, options, success){
  655.        
  656.         var rc = this.getById(options.params[this.paramNames.active_node]);
  657.        
  658.         if (success && rc) {
  659.            
  660.             this.setNodeLoaded(rc, true);
  661.             this.setNodeExpanded(rc, true);
  662.             this.fireEvent('expandnode', this, rc);
  663.            
  664.         } else {
  665.            
  666.             this.fireEvent('expandnodefailed', this, options.params[this.paramNames.active_node], rc);
  667.            
  668.         }   // if
  669.        
  670.     },
  671.    
  672.     /**
  673.      * Returns loaded node id from the load options.
  674.      *
  675.      * @access public
  676.      */
  677.     getLoadedNodeIdFromOptions: function(options){
  678.        
  679.         var result = null;
  680.        
  681.         if (
  682.             options && options.params &&
  683.             options.params[this.paramNames.active_node]
  684.         ) {
  685.            
  686.             result = options.params[this.paramNames.active_node];
  687.            
  688.         }   // if
  689.        
  690.         return result;
  691.        
  692.     },
  693.    
  694.     /**
  695.      * Returns start offset from the load options.
  696.      */
  697.     getPageOffsetFromOptions: function(options){
  698.         var result = 0;
  699.         if (options && options.params && options.params[this.paramNames.start]) {
  700.             result = parseInt(options.params[this.paramNames.start], 10);
  701.             if (isNaN(result)) {
  702.                 result = 0;
  703.             }
  704.         }
  705.         return result;
  706.     },
  707.    
  708.     // Public
  709.     hasNextSiblingNode: function(rc){
  710.         return this.getNodeNextSibling(rc) !== null;
  711.     },
  712.    
  713.     // Public
  714.     hasPrevSiblingNode: function(rc){
  715.         return this.getNodePrevSibling(rc) !== null;
  716.     },
  717.    
  718.     // Public
  719.     hasChildNodes: function(rc){
  720.         return this.getNodeChildrenCount(rc) > 0;
  721.     },
  722.    
  723.     // Public
  724.     getNodeAncestors: function(rc){
  725.        
  726.         var ancestors = [], parent;
  727.        
  728.         parent = this.getNodeParent(rc);
  729.        
  730.         while (parent) {
  731.             ancestors.push(parent);
  732.             parent = this.getNodeParent(parent);
  733.         }
  734.        
  735.         return ancestors;
  736.        
  737.     },
  738.    
  739.     // Public
  740.     getNodeChildrenCount: function(rc){
  741.         return this.getNodeChildren(rc).length;
  742.     },
  743.    
  744.     // Public
  745.     getNodeNextSibling: function(rc) {
  746.        
  747.         var siblings, parent, index, result = null;
  748.        
  749.         parent = this.getNodeParent(rc);
  750.        
  751.         if (parent) {
  752.            
  753.             siblings = this.getNodeChildren(parent);
  754.            
  755.         } else {
  756.            
  757.             siblings = this.getRootNodes();
  758.            
  759.         }
  760.        
  761.         index = siblings.indexOf(rc);
  762.        
  763.         if (index < siblings.length - 1) {
  764.             result = siblings[index + 1];
  765.         }
  766.        
  767.         return result;
  768.     },
  769.    
  770.     // Public
  771.     getNodePrevSibling: function(rc){
  772.        
  773.         var siblings, parent, index, result = null;
  774.        
  775.         parent = this.getNodeParent(rc);
  776.        
  777.         if (parent) {
  778.            
  779.             siblings = this.getNodeChildren(parent);
  780.            
  781.         } else {
  782.            
  783.             siblings = this.getRootNodes();
  784.            
  785.         }
  786.        
  787.         index = siblings.indexOf(rc);
  788.        
  789.         if (index > 0) {
  790.             result = siblings[index - 1];
  791.         }
  792.        
  793.         return result;
  794.     },
  795.    
  796.     // Abstract tree support methods.
  797.     // -----------------------------------------------------------------------------------------------
  798.    
  799.     // Public - Abstract
  800.     getRootNodes: function(){
  801.         throw 'Abstract method call';
  802.     },
  803.    
  804.     // Public - Abstract
  805.     getNodeDepth: function(rc){
  806.         throw 'Abstract method call';
  807.     },
  808.    
  809.     // Public - Abstract
  810.     getNodeParent: function(rc){
  811.         throw 'Abstract method call';
  812.     },
  813.    
  814.     // Public - Abstract
  815.     getNodeChildren: function(rc){
  816.         throw 'Abstract method call';
  817.     },
  818.    
  819.     // Public - Abstract
  820.     addToNode: function(parent, child){
  821.         throw 'Abstract method call';
  822.     },
  823.    
  824.     // Public - Abstract
  825.     removeFromNode: function(parent, child){
  826.         throw 'Abstract method call';
  827.     },
  828.    
  829.     // Paging support methods.
  830.     // -----------------------------------------------------------------------------------------------
  831.     /**
  832.      * Returns top level node page offset.
  833.      *
  834.      * @access public
  835.      * @return {Integer}
  836.      */
  837.     getPageOffset: function(){
  838.        
  839.         return this.page_offset;
  840.        
  841.     },
  842.    
  843.     /**
  844.      * Returns active node page offset.
  845.      *
  846.      * @access public
  847.      * @return {Integer}
  848.      */
  849.     getActiveNodePageOffset: function(){
  850.        
  851.         var result;
  852.        
  853.         if (this.active_node) {
  854.            
  855.             result = this.getNodeChildrenOffset(this.active_node);
  856.            
  857.         } else {
  858.            
  859.             result = this.getPageOffset();
  860.            
  861.         }
  862.        
  863.         return result;
  864.     },
  865.    
  866.     /**
  867.      * Returns active node children count.
  868.      *
  869.      * @access public
  870.      * @return {Integer}
  871.      */
  872.     getActiveNodeCount: function(){
  873.        
  874.         var result;
  875.        
  876.         if (this.active_node) {
  877.            
  878.             result = this.getNodeChildrenCount(this.active_node);
  879.            
  880.         } else {
  881.            
  882.             result = this.getRootNodes().length;
  883.            
  884.         }
  885.        
  886.         return result;
  887.     },
  888.    
  889.     /**
  890.      * Returns active node total children count.
  891.      *
  892.      * @access public
  893.      * @return {Integer}
  894.      */
  895.     getActiveNodeTotalCount: function(){
  896.        
  897.         var result;
  898.        
  899.         if (this.active_node) {
  900.            
  901.             result = this.getNodeChildrenTotalCount(this.active_node);
  902.            
  903.         } else {
  904.            
  905.             result = this.getTotalCount();
  906.            
  907.         }
  908.        
  909.         return result;
  910.     }
  911.    
  912. });
  913.  
  914. /**
  915.  * Tree store for adjacency list tree representation.
  916.  */
  917. Ext.ux.maximgb.treegrid.AdjacencyListStore = Ext.extend(Ext.ux.maximgb.treegrid.AbstractTreeStore, {
  918.     /**
  919.      * @cfg {String} parent_id_field_name Record parent id field name.
  920.      */
  921.     parent_id_field_name: '_parent',
  922.    
  923.     _cache: {},
  924.    
  925.     constructor: function(config){
  926.        
  927.         Ext.ux.maximgb.treegrid.AdjacencyListStore.superclass.constructor.call(this, config);
  928.        
  929.         this.clearCache();
  930.        
  931.         this.on("datachanged", function() {
  932.  
  933.             this.clearCache();
  934.            
  935.         });
  936.        
  937.     },
  938.    
  939.     /**
  940.      * Cache clearance required before sort.
  941.     **/
  942.     applyTreeSort: function() {
  943.        
  944.         this.clearCache();
  945.        
  946.         return Ext.ux.maximgb.treegrid.AdjacencyListStore.superclass.applyTreeSort.call(this);
  947.        
  948.     },
  949.    
  950.     clearCache: function() {
  951.  
  952.         this._cache = {
  953.             getRootNodes: null,
  954.             getNodeChildren: {}
  955.         };
  956.        
  957.     },
  958.    
  959.     load: function(options){
  960.        
  961.         this.clearCache();
  962.        
  963.         return Ext.ux.maximgb.treegrid.AdjacencyListStore.superclass.load.call(this, options);
  964.        
  965.     },
  966.    
  967.     loadRecords: function(o, options, success){
  968.        
  969.         var ret = Ext.ux.maximgb.treegrid.AdjacencyListStore.superclass.loadRecords.call(this, o, options, success);
  970.        
  971.         /**
  972.          * Collect if node really loaded (have a childrens)
  973.         **/
  974.        
  975.         var i, len,
  976.             map = {},
  977.             records = this.getRange()
  978.         ;
  979.        
  980.         for (i = 0, len = records.length; i < len; i++) {
  981.            
  982.             map[records[i].id] = records[i];
  983.            
  984.         }   // for
  985.        
  986.         for (i = 0; i < len; i++) {
  987.            
  988.             var p = records[i].data[this.parent_id_field_name];
  989.            
  990.             if ( p == null ) {
  991.                 continue; }
  992.        
  993.             if( map[p] != undefined ) {
  994.                 map[p].ux_maximgb_treegrid_loaded = true; }
  995.                    
  996.         }   // for
  997.        
  998.         return ret;
  999.        
  1000.     },
  1001.    
  1002.     getRootNodes: function() {
  1003.        
  1004.         if( this._cache.getRootNodes ) {
  1005.             return this._cache.getRootNodes; }
  1006.        
  1007.         var i, len, result = [], records = this.getRange();
  1008.        
  1009.         for (i = 0, len = records.length; i < len; i++) {
  1010.            
  1011.             if (records[i].data[this.parent_id_field_name] == null) {
  1012.                 result.push(records[i]); }
  1013.            
  1014.         }   // for
  1015.        
  1016.         return this._cache.getRootNodes = result;
  1017.     },
  1018.    
  1019.     getNodeDepth: function(rc){
  1020.        
  1021.         return this.getNodeAncestors(rc).length;
  1022.        
  1023.     },
  1024.    
  1025.     getNodeParent: function(rc){
  1026.        
  1027.         if( !rc ) {
  1028.             return; }
  1029.        
  1030.         return this.getById( rc.data[this.parent_id_field_name] );
  1031.        
  1032.     },
  1033.  
  1034.     getNodeChildren: function(rc){
  1035.  
  1036.         if( this._cache.getNodeChildren[rc.id] != undefined ) {
  1037.             return this._cache.getNodeChildren[rc.id]; }
  1038.            
  1039.         this._cache.getNodeChildren[rc.id] = [];
  1040.  
  1041.         var i, len, result = [], records = this.getRange();
  1042.        
  1043.         for (i = 0, len = records.length; i < len; i++) {
  1044.            
  1045.             var parent = records[i].data[this.parent_id_field_name];
  1046.            
  1047.             if( this._cache.getNodeChildren[parent] == undefined ) {
  1048.                 this._cache.getNodeChildren[parent] = []; }
  1049.                
  1050.             if( this._cache.getNodeChildren[records[i].id] == undefined ) {
  1051.                 this._cache.getNodeChildren[records[i].id] = []; }
  1052.                
  1053.             this._cache.getNodeChildren[parent].push(records[i]);
  1054.            
  1055.         }   // for
  1056.        
  1057.         return this._cache.getNodeChildren[rc.id] || [];
  1058.        
  1059.     }
  1060.    
  1061. });
  1062.  
  1063. /**
  1064.  * Tree store for nested set tree representation.
  1065.  */
  1066. Ext.ux.maximgb.treegrid.NestedSetStore = Ext.extend(Ext.ux.maximgb.treegrid.AbstractTreeStore, {
  1067.     /**
  1068.      * @cfg {String} left_field_name Record NS-left bound field name.
  1069.      */
  1070.     left_field_name: '_lft',
  1071.    
  1072.     /**
  1073.      * @cfg {String} right_field_name Record NS-right bound field name.
  1074.      */
  1075.     right_field_name: '_rgt',
  1076.    
  1077.     /**
  1078.      * @cfg {String} level_field_name Record NS-level field name.
  1079.      */
  1080.     level_field_name: '_level',
  1081.    
  1082.     /**
  1083.      * @cfg {Number} root_node_level Root node level.
  1084.      */
  1085.     root_node_level: 1,
  1086.    
  1087.     getRootNodes: function(){
  1088.         var i, len, result = [], records = this.data.getRange();
  1089.        
  1090.         for (i = 0, len = records.length; i < len; i++) {
  1091.             if (records[i].get(this.level_field_name) == this.root_node_level) {
  1092.                 result.push(records[i]);
  1093.             }
  1094.         }
  1095.        
  1096.         return result;
  1097.     },
  1098.    
  1099.     getNodeDepth: function(rc){
  1100.         return rc.get(this.level_field_name) - this.root_node_level;
  1101.     },
  1102.    
  1103.     getNodeParent: function(rc){
  1104.         var result = null, rec, records = this.data.getRange(), i, len, lft, r_lft, rgt, r_rgt, level, r_level;
  1105.        
  1106.         lft = rc.get(this.left_field_name);
  1107.         rgt = rc.get(this.right_field_name);
  1108.         level = rc.get(this.level_field_name);
  1109.        
  1110.         for (i = 0, len = records.length; i < len; i++) {
  1111.             rec = records[i];
  1112.             r_lft = rec.get(this.left_field_name);
  1113.             r_rgt = rec.get(this.right_field_name);
  1114.             r_level = rec.get(this.level_field_name);
  1115.            
  1116.             if (r_level == level - 1 &&
  1117.             r_lft < lft &&
  1118.             r_rgt > rgt) {
  1119.                 result = rec;
  1120.                 break;
  1121.             }
  1122.         }
  1123.        
  1124.         return result;
  1125.     },
  1126.    
  1127.     getNodeChildren: function(rc){
  1128.         var lft, r_lft, rgt, r_rgt, level, r_level, records, rec, result = [];
  1129.        
  1130.         records = this.data.getRange();
  1131.        
  1132.         lft = rc.get(this.left_field_name);
  1133.         rgt = rc.get(this.right_field_name);
  1134.         level = rc.get(this.level_field_name);
  1135.        
  1136.         for (i = 0, len = records.length; i < len; i++) {
  1137.             rec = records[i];
  1138.             r_lft = rec.get(this.left_field_name);
  1139.             r_rgt = rec.get(this.right_field_name);
  1140.             r_level = rec.get(this.level_field_name);
  1141.            
  1142.             if (r_level == level + 1 &&
  1143.             r_lft > lft &&
  1144.             r_rgt < rgt) {
  1145.                 result.push(rec);
  1146.             }
  1147.         }
  1148.        
  1149.         return result;
  1150.     }
  1151. });
  1152.  
  1153. Ext.ux.maximgb.treegrid.GridView = Ext.extend(Ext.grid.GridView, {
  1154.    
  1155.     // private
  1156.     breadcrumbs_el: null,
  1157.     forceFit: false,
  1158.     unrendered: {},
  1159.     useArrows: false,
  1160.     noElbowOnLeaf: false,
  1161.    
  1162.     // private - overriden
  1163.     initTemplates: function(){
  1164.        
  1165.         var ts = this.templates || {};
  1166.        
  1167.         ts.master = new Ext.Template(
  1168.             '<div class="x-grid3" hidefocus="true">',
  1169.             '<div class="x-grid3-viewport">',
  1170.             '<div class="x-grid3-header">',
  1171.            
  1172.             // Breadcrumbs
  1173.             '<div class="x-grid3-header-inner" style="display:none">',
  1174.             '<div class="x-grid3-header-offset">',
  1175.             '<div class="ux-maximgb-treegrid-breadcrumbs">&#160;</div>',
  1176.             '</div>',
  1177.             '</div>',
  1178.             '<div class="x-clear"></div>',
  1179.             // End of breadcrumbs
  1180.    
  1181.             // Header
  1182.             '<div class="x-grid3-header-inner">',
  1183.             '<div class="x-grid3-header-offset">{header}</div>',
  1184.             '</div>',
  1185.             '<div class="x-clear"></div>',
  1186.            
  1187.             // End of header
  1188.             '</div>',
  1189.            
  1190.             // Scroller
  1191.             '<div class="x-grid3-scroller">',
  1192.             '<div class="x-grid3-body', (this.useArrows ? " x-tree-arrows " : "")  ,'">{body}</div>',
  1193.             '<a href="#" class="x-grid3-focus" tabIndex="-1"></a>',
  1194.             '</div>',
  1195.            
  1196.             // End of scroller
  1197.             '</div>',
  1198.            
  1199.             '<div class="x-grid3-resize-marker">&#160;</div>',
  1200.             '<div class="x-grid3-resize-proxy">&#160;</div>',
  1201.             '</div>'
  1202.         );
  1203.        
  1204.         ts.row = new Ext.Template(
  1205.             '<div class="x-grid3-row {alt} ux-maximgb-treegrid-level ux-maximgb-treegrid-level-{level}" style="{tstyle} {display_style}" rowIndex="{rowIndex}">',
  1206.             '<table class="x-grid3-row-table" border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
  1207.             '<tbody>',
  1208.             '<tr>{cells}</tr>',
  1209.             (this.enableRowBody ?
  1210.                 '<tr class="x-grid3-row-body-tr" style="{bodyStyle}">' +
  1211.                 '<td colspan="{cols}" class="x-grid3-body-cell" tabIndex="0" hidefocus="on">' +
  1212.                 '<div class="x-grid3-row-body">{body}</div>' +
  1213.                 '</td>' + '</tr>' : ''
  1214.             ),
  1215.             '</tbody>',
  1216.             '</table>',
  1217.             '</div>'
  1218.         );
  1219.        
  1220.         ts.cell = new Ext.Template(
  1221.             '<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} {css}" style="{style}" tabIndex="0" {cellAttr}>',
  1222.             '{treeui}',
  1223.             '<div class="x-grid3-cell-inner x-grid3-col-{id}" unselectable="on" {attr}>{value}</div>',
  1224.             '</td>'
  1225.         );
  1226.        
  1227.         ts.treeui = new Ext.Template(
  1228.             '<div class="ux-maximgb-treegrid-uiwrap" style="width: {wrap_width}px">',
  1229.             '{elbow_line}',
  1230.             '<div style="left: {left}px" class="{cls}">&#160;</div>',
  1231.             '</div>'
  1232.         );
  1233.        
  1234.         ts.elbow_line = new Ext.Template('<div style="left: {left}px" class="{cls}">&#160;</div>');
  1235.        
  1236.         ts.brd_item = new Ext.Template('<a href="#" id="ux-maximgb-treegrid-brditem-{id}" class="ux-maximgb-treegrid-brditem" ext:qtip="{title}">{caption}</a>');
  1237.        
  1238.         this.templates = ts;
  1239.        
  1240.         Ext.ux.maximgb.treegrid.GridView.superclass.initTemplates.call(this);
  1241.        
  1242.     },
  1243.    
  1244.     // private - overriden
  1245.     initElements: function() {
  1246.        
  1247.         var E = Ext.Element;
  1248.        
  1249.         var el = this.grid.getGridEl().dom.firstChild;
  1250.         var cs = el.childNodes;
  1251.        
  1252.         this.el = new E(el);
  1253.        
  1254.         this.mainWrap = new E(cs[0]);
  1255.         this.mainHd = new E(this.mainWrap.dom.firstChild);
  1256.        
  1257.         if (this.grid.hideHeaders) {
  1258.             this.mainHd.setDisplayed(false);
  1259.         }
  1260.        
  1261.         // ----- Modification start
  1262.         //Original: this.innerHd = this.mainHd.dom.firstChild;
  1263.         this.innerHd = this.mainHd.dom.childNodes[2];
  1264.         // ----- End of modification
  1265.         this.scroller = new E(this.mainWrap.dom.childNodes[1]);
  1266.        
  1267.         if (this.forceFit) {
  1268.             this.scroller.setStyle('overflow-x', 'hidden');
  1269.         }
  1270.         this.mainBody = new E(this.scroller.dom.firstChild);
  1271.        
  1272.         this.focusEl = new E(this.scroller.dom.childNodes[1]);
  1273.         this.focusEl.swallowEvent("click", true);
  1274.        
  1275.         this.resizeMarker = new E(cs[1]);
  1276.         this.resizeProxy = new E(cs[2]);
  1277.        
  1278.         this.breadcrumbs_el = this.el.child('.ux-maximgb-treegrid-breadcrumbs');
  1279.         this.setRootBreadcrumbs();
  1280.        
  1281.     },
  1282.    
  1283.     refresh: function(headersToo) {
  1284.        
  1285.         /**
  1286.          * Clear unrendered map on refresh
  1287.         **/
  1288.         this.unrendered = {};
  1289.        
  1290.         Ext.ux.maximgb.treegrid.GridView.superclass.refresh.call(this, headersToo);
  1291.        
  1292.     },
  1293.    
  1294.     // Private - Overriden
  1295.     doRender: function(cs, rs, ds, startRow, colCount, stripe){
  1296.  
  1297.         var ts = this.templates,
  1298.             ct = ts.cell,
  1299.             rt = ts.row,
  1300.             last = colCount - 1
  1301.         ;
  1302.        
  1303.         var tstyle = 'width:' + this.getTotalWidth() + ';';
  1304.        
  1305.         // buffers
  1306.         var buf = [],
  1307.             cb,
  1308.             c,
  1309.             p = {},
  1310.             rp = {
  1311.                 tstyle: tstyle
  1312.             },
  1313.             r
  1314.         ;
  1315.  
  1316.         for (var j = 0, len = rs.length; j < len; j++) {
  1317.            
  1318.             r = rs[j];
  1319.             cb = [];
  1320.            
  1321.             /**
  1322.              * Expand-Render
  1323.              * Check if node should be rendered
  1324.             **/
  1325.             var r_parent = this.ds.getNodeParent(r);
  1326.            
  1327.             if(
  1328.                 r_parent != undefined &&
  1329.                 !this.ds.isExpandedNode(r_parent)
  1330.             ) {
  1331.                
  1332.                 var r_parent_index = this.ds.indexOfId(r_parent.id);
  1333.                
  1334.                 this.unrendered[r_parent_index] = this.unrendered[r_parent_index] || [];
  1335.                 this.unrendered[r_parent_index].push(j + startRow);
  1336.                
  1337.                 continue;
  1338.                
  1339.             }   // if
  1340.            
  1341.             var rowIndex = (j + startRow);
  1342.            
  1343.             for(var i = 0; i < colCount; i++) {
  1344.                
  1345.                 c = cs[i];
  1346.                 p.id = c.id;
  1347.                 p.css = i == 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '');
  1348.                 p.attr = p.cellAttr = "";
  1349.                
  1350.                 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
  1351.                 p.style = c.style;
  1352.                
  1353.                 if (p.value == undefined || p.value === "") {
  1354.                     p.value = "&#160;";
  1355.                 }
  1356.                
  1357.                 if (r.dirty && r.modified[c.name] !== undefined ) {
  1358.                     p.css += ' x-grid3-dirty-cell';
  1359.                 }
  1360.                
  1361.                 // ----- Modification start
  1362.                 if (c.id == this.grid.master_column_id) {
  1363.                    
  1364.                     p.treeui = this.renderCellTreeUI(r, ds);
  1365.                    
  1366.                 } else {
  1367.                    
  1368.                     p.treeui = '';
  1369.                    
  1370.                 }
  1371.                
  1372.                 // ----- End of modification
  1373.                 cb[cb.length] = ct.apply(p);
  1374.                
  1375.             }
  1376.            
  1377.             var alt = [];
  1378.            
  1379.             if (stripe && ((rowIndex + 1) % 2 == 0)) {
  1380.                 alt[0] = "x-grid3-row-alt"; }
  1381.            
  1382.             if (r.dirty) {
  1383.                 alt[1] = " x-grid3-dirty-row"; }
  1384.            
  1385.             rp.cols = colCount;
  1386.            
  1387.             if (this.getRowClass) {
  1388.                 alt[2] = this.getRowClass(r, rowIndex, rp, ds); }
  1389.            
  1390.             rp.alt = alt.join(" ");
  1391.             rp.cells = cb.join("");
  1392.            
  1393.             // ----- Modification start
  1394.             if (!ds.isVisibleNode(r)) {
  1395.                
  1396.                 rp.display_style = 'display: none;';
  1397.            
  1398.             } else {
  1399.                
  1400.                 rp.display_style = '';
  1401.            
  1402.             }
  1403.            
  1404.             rp.level = ds.getNodeDepth(r);
  1405.             rp.rowIndex = rowIndex;
  1406.            
  1407.             // ----- End of modification
  1408.             buf[buf.length] = rt.apply(rp);
  1409.            
  1410.         }
  1411.        
  1412.         return buf.join("");
  1413.        
  1414.     },
  1415.    
  1416.     processRows : function(startRow, skipStripe){
  1417.        
  1418.         if(!this.ds || this.ds.getCount() < 1) {
  1419.             return; }
  1420.        
  1421.         var rows = this.getRows();
  1422.        
  1423.         skipStripe = skipStripe || !this.grid.stripeRows;
  1424.        
  1425.         startRow = startRow || 0;
  1426.        
  1427.         Ext.each(rows, function(row, idx){
  1428.            
  1429.             /**
  1430.              * Expand-render
  1431.              * Check if rows array has real-row.
  1432.             **/
  1433.             if( !row ) {
  1434.                 return; }
  1435.            
  1436.             row.rowIndex  = idx;
  1437.             row.className = row.className.replace(this.rowClsRe, ' ');
  1438.            
  1439.             if (!skipStripe && (row.rowIndex + 1) % 2 === 0) {
  1440.                 row.className += ' x-grid3-row-alt'; }
  1441.            
  1442.         });
  1443.        
  1444.         // add first/last-row classes
  1445.         if(startRow === 0){
  1446.             Ext.fly(rows[0]).addClass(this.firstRowCls);
  1447.         }
  1448.        
  1449.         Ext.fly(rows[rows.length - 1]).addClass(this.lastRowCls);
  1450.     },
  1451.    
  1452.     getCell : function(row, col) {
  1453.            
  1454.         var row = this.getRow(row);
  1455.            
  1456.         if( !row ) {
  1457.             return; }
  1458.            
  1459.         var cs = Ext.get(row).query( this.cellSelector );
  1460.            
  1461.         if( cs[col] == undefined ) {
  1462.             return false; }
  1463.                
  1464.         return cs[col];
  1465.            
  1466.     },
  1467.    
  1468.     getRows : function() {
  1469.        
  1470.         if( !this.hasRows() ) {
  1471.             return []; }
  1472.        
  1473.         var rows = this.mainBody.dom.childNodes;
  1474.        
  1475.         /**
  1476.          * Fix of index, required for expand-render
  1477.          * Index based on rowIndex attribute, nor on dom position.
  1478.         **/
  1479.        
  1480.         var r = [];
  1481.        
  1482.         Ext.each(rows, function(row) {
  1483.  
  1484.             var index = parseInt( row.getAttribute("rowIndex") );
  1485.            
  1486.             r[index] = row;
  1487.             r[index].rowIndex = index;
  1488.            
  1489.         });
  1490.        
  1491.         return r;
  1492.        
  1493.     },
  1494.        
  1495.     renderCellTreeUI: function(record, store){
  1496.  
  1497.         if( this.noElbowOnLeaf && store.isLeafNode(record) ) {
  1498.             return ""; }
  1499.  
  1500.         var tpl = this.templates.treeui,
  1501.             line_tpl = this.templates.elbow_line,
  1502.             tpl_data = {},
  1503.             rec, parent,
  1504.             depth = level = store.getNodeDepth(record)
  1505.         ;
  1506.        
  1507.         tpl_data.wrap_width = (depth + 1) * 16;
  1508.        
  1509.         if (level > 0) {
  1510.            
  1511.             tpl_data.elbow_line = '';
  1512.             rec = record;
  1513.             left = 0;
  1514.            
  1515.             while (level--) {
  1516.                
  1517.                 parent = store.getNodeParent(rec);
  1518.                
  1519.                 if (parent) {
  1520.                    
  1521.                     if (store.hasNextSiblingNode(parent)) {
  1522.                        
  1523.                         tpl_data.elbow_line = line_tpl.apply({
  1524.                             left: level * 16,
  1525.                             cls: 'ux-maximgb-treegrid-elbow-line'
  1526.                         }) +
  1527.                         tpl_data.elbow_line;
  1528.                        
  1529.                     } else {
  1530.                        
  1531.                         tpl_data.elbow_line = line_tpl.apply({
  1532.                             left: level * 16,
  1533.                             cls: 'ux-maximgb-treegrid-elbow-empty'
  1534.                         }) +
  1535.                         tpl_data.elbow_line;
  1536.                        
  1537.                     }
  1538.                    
  1539.                 } else {    
  1540.                    
  1541.                     throw [
  1542.                         "Tree inconsistency can't get level ",
  1543.                         level + 1,
  1544.                         " node(id=", rec.id, ") parent."
  1545.                     ].join("");
  1546.                
  1547.                 }
  1548.                  
  1549.                 rec = parent;
  1550.                
  1551.             }
  1552.         }
  1553.        
  1554.         if (store.isLeafNode(record)) {
  1555.            
  1556.             if (store.hasNextSiblingNode(record)) {
  1557.                
  1558.                 tpl_data.cls = 'ux-maximgb-treegrid-elbow';
  1559.                
  1560.             } else {
  1561.                
  1562.                 tpl_data.cls = 'ux-maximgb-treegrid-elbow-end';
  1563.                
  1564.             }
  1565.            
  1566.         } else {
  1567.            
  1568.             tpl_data.cls = 'ux-maximgb-treegrid-elbow-active ';
  1569.            
  1570.             if (store.isExpandedNode(record)) {
  1571.                
  1572.                 if (store.hasNextSiblingNode(record)) {
  1573.                    
  1574.                     tpl_data.cls += 'ux-maximgb-treegrid-elbow-minus';
  1575.                    
  1576.                 } else {
  1577.                    
  1578.                     tpl_data.cls += 'ux-maximgb-treegrid-elbow-end-minus';
  1579.                    
  1580.                 }   // if
  1581.                
  1582.             } else {
  1583.                
  1584.                 if (store.hasNextSiblingNode(record)) {
  1585.                    
  1586.                     tpl_data.cls += 'ux-maximgb-treegrid-elbow-plus';
  1587.                    
  1588.                 } else {
  1589.                    
  1590.                     tpl_data.cls += 'ux-maximgb-treegrid-elbow-end-plus';
  1591.                    
  1592.                 }   // if
  1593.                
  1594.             }   // if
  1595.            
  1596.         }   // if
  1597.        
  1598.         tpl_data.left = 1 + depth * 16;
  1599.        
  1600.         return tpl.apply(tpl_data);
  1601.        
  1602.     },
  1603.    
  1604.     refreshRow : function(record){
  1605.        
  1606.         var ds = this.ds, index;
  1607.        
  1608.         if(typeof record == 'number'){
  1609.            
  1610.             index  = record;
  1611.             record = ds.getAt(index);
  1612.            
  1613.             if( !record ) {
  1614.                 return; }
  1615.            
  1616.         } else {
  1617.            
  1618.             index = ds.indexOf(record);
  1619.            
  1620.             if( index < 0 ){
  1621.                 return; }
  1622.            
  1623.         }
  1624.        
  1625.         var cls = [];
  1626.  
  1627.         this.insertRows(ds, index, index, true);
  1628.         this.getRow(index).rowIndex = index;
  1629.         this.onRemove(ds, record, index, true);
  1630.         this.fireEvent("rowupdated", this, index, record);
  1631.        
  1632.     },
  1633.    
  1634.     onRowOut : function(e, t){
  1635.  
  1636.         var row = this.findRowIndex(t);
  1637.          
  1638.         if( row == undefined ) {
  1639.             return; }
  1640.          
  1641.         if( (row) !== false && !e.within(this.getRow(row), true) ) {
  1642.            
  1643.             this.removeRowClass(row, "x-grid3-row-over");
  1644.            
  1645.         }   // if
  1646.        
  1647.     },
  1648.  
  1649.  
  1650.     // Private
  1651.     getBreadcrumbsEl: function(){
  1652.        
  1653.         return this.breadcrumbs_el;
  1654.        
  1655.     },
  1656.    
  1657.     updateColumnWidth : function(col, width){
  1658.         var w = this.getColumnWidth(col);
  1659.         var tw = this.getTotalWidth();
  1660.         this.innerHd.firstChild.style.width = this.getOffsetWidth();
  1661.         this.innerHd.firstChild.firstChild.style.width = tw;
  1662.         this.mainBody.dom.style.width = tw;
  1663.         var hd = this.getHeaderCell(col);
  1664.         hd.style.width = w;
  1665.  
  1666.         var ns = this.getRows(), row;
  1667.         for(var i = 0, len = ns.length; i < len; i++){
  1668.                        
  1669.             row = ns[i];
  1670.            
  1671.             if( !row ) {
  1672.                 continue; }
  1673.            
  1674.             row.style.width = tw;
  1675.            
  1676.             if(row.firstChild){
  1677.                 row.firstChild.style.width = tw;
  1678.                 row.firstChild.rows[0].childNodes[col].style.width = w;
  1679.             }
  1680.         }
  1681.  
  1682.         this.onColumnWidthUpdated(col, w, tw);
  1683.     },
  1684.  
  1685.     // private
  1686.     updateColumnHidden : function(col, hidden){
  1687.         var tw = this.getTotalWidth();
  1688.         this.innerHd.firstChild.style.width = this.getOffsetWidth();
  1689.         this.innerHd.firstChild.firstChild.style.width = tw;
  1690.         this.mainBody.dom.style.width = tw;
  1691.         var display = hidden ? 'none' : '';
  1692.  
  1693.         var hd = this.getHeaderCell(col);
  1694.         hd.style.display = display;
  1695.  
  1696.         var ns = this.getRows(), row;
  1697.         for(var i = 0, len = ns.length; i < len; i++){
  1698.            
  1699.             row = ns[i];
  1700.            
  1701.             if( !row ) {
  1702.                 continue; }
  1703.            
  1704.             row.style.width = tw;
  1705.            
  1706.             if(row.firstChild){
  1707.                 row.firstChild.style.width = tw;
  1708.                 row.firstChild.rows[0].childNodes[col].style.display = display;
  1709.             }
  1710.         }
  1711.  
  1712.         this.onColumnHiddenUpdated(col, hidden, tw);
  1713.         delete this.lastViewWidth; // force recalc
  1714.         this.layout();
  1715.     },
  1716.    
  1717.     // Private
  1718.     expandRow: function(record, initial){
  1719.        
  1720.         var ds = this.ds, i, len, row, pmel, children, index, child_index;
  1721.        
  1722.         if (typeof record == 'number') {
  1723.            
  1724.             index = record;
  1725.             record = ds.getAt(index);
  1726.            
  1727.         } else {
  1728.            
  1729.             index = ds.indexOf(record);
  1730.            
  1731.         }
  1732.        
  1733.         row = this.getRow(index);
  1734.        
  1735.         if( !row ) {
  1736.             return; }
  1737.  
  1738.         /**
  1739.          * Render child rows on expansion
  1740.         **/
  1741.         if( this.unrendered[index] != undefined ) {
  1742.            
  1743.             var view = this;
  1744.             var childs_rows = this.unrendered[index];
  1745.             var childs_rows_html = "";
  1746.            
  1747.             Ext.each(childs_rows, function(child_row) {
  1748.                
  1749.                 childs_rows_html += view.renderRows(child_row, child_row);
  1750.                
  1751.             });
  1752.            
  1753.             Ext.DomHelper.insertHtml('afterEnd', row, childs_rows_html);
  1754.            
  1755.             var rows = view.getRows();
  1756.            
  1757.             // Setup rowindex
  1758.             Ext.each(childs_rows, function(child_row) {
  1759.                 rows[child_row].rowIndex = child_row; });
  1760.            
  1761.             delete this.unrendered[index];
  1762.            
  1763.         }   // if
  1764.        
  1765.         pmel = Ext.fly(row).child('.ux-maximgb-treegrid-elbow-active');
  1766.        
  1767.         if (pmel) {
  1768.            
  1769.             if (ds.hasNextSiblingNode(record)) {
  1770.                 pmel.removeClass('ux-maximgb-treegrid-elbow-plus');
  1771.                 pmel.removeClass('ux-maximgb-treegrid-elbow-end-plus');
  1772.                 pmel.addClass('ux-maximgb-treegrid-elbow-minus');
  1773.             } else {
  1774.                 pmel.removeClass('ux-maximgb-treegrid-elbow-plus');
  1775.                 pmel.removeClass('ux-maximgb-treegrid-elbow-end-plus');
  1776.                 pmel.addClass('ux-maximgb-treegrid-elbow-end-minus');
  1777.             }
  1778.            
  1779.             if (ds.isVisibleNode(record)) {
  1780.                
  1781.                 children = ds.getNodeChildren(record);
  1782.                
  1783.                 for (i = 0, len = children.length; i < len; i++) {
  1784.                    
  1785.                     child_index = ds.indexOf(children[i]);
  1786.                     row = this.getRow(child_index);
  1787.                    
  1788.                     if( !row) {
  1789.                         continue; }
  1790.                    
  1791.                     Ext.fly(row).setStyle('display', 'block');
  1792.                    
  1793.                     if (ds.isExpandedNode(children[i])) {
  1794.                         this.expandRow(child_index); }
  1795.                    
  1796.                 }
  1797.             }
  1798.         }
  1799.     },
  1800.    
  1801.     collapseRow: function(record) {
  1802.        
  1803.         var ds = this.ds, i, len, children, row, index;
  1804.        
  1805.         if (typeof record == 'number') {
  1806.            
  1807.             index = record;
  1808.             record = ds.getAt(index);
  1809.            
  1810.         } else {
  1811.            
  1812.             index = ds.indexOf(record);
  1813.            
  1814.         }   // if
  1815.        
  1816.         row  = this.getRow(index);
  1817.         pmel = Ext.fly(row).child('.ux-maximgb-treegrid-elbow-active');
  1818.        
  1819.         if (pmel) {
  1820.            
  1821.             if (ds.hasNextSiblingNode(record)) {
  1822.                
  1823.                 pmel.removeClass('ux-maximgb-treegrid-elbow-minus');
  1824.                 pmel.removeClass('ux-maximgb-treegrid-elbow-end-minus');
  1825.                 pmel.addClass('ux-maximgb-treegrid-elbow-plus');
  1826.                
  1827.             } else {
  1828.                
  1829.                 pmel.removeClass('ux-maximgb-treegrid-elbow-minus');
  1830.                 pmel.removeClass('ux-maximgb-treegrid-elbow-end-minus');
  1831.                 pmel.addClass('ux-maximgb-treegrid-elbow-end-plus');
  1832.                
  1833.             }   // if
  1834.            
  1835.             children = ds.getNodeChildren(record);
  1836.            
  1837.             for (i = 0, len = children.length; i < len; i++) {
  1838.                
  1839.                 index = ds.indexOf(children[i]);
  1840.                 row   = this.getRow(index);
  1841.  
  1842.                 if( !row ) {
  1843.                     continue; }
  1844.                    
  1845.                 Ext.fly(row).setStyle('display', 'none');
  1846.                 this.collapseRow(index);
  1847.                
  1848.             }   // for
  1849.            
  1850.         }   // if
  1851.        
  1852.     },
  1853.    
  1854.     /**
  1855.      * @access private
  1856.      */
  1857.     initData: function(ds, cm){
  1858.        
  1859.         Ext.ux.maximgb.treegrid.GridView.superclass.initData.call(this, ds, cm);
  1860.        
  1861.         if (this.ds) {
  1862.             this.ds.un('activenodechange', this.onStoreActiveNodeChange, this);
  1863.             this.ds.un('expandnode', this.onStoreExpandNode, this);
  1864.             this.ds.un('collapsenode', this.onStoreCollapseNode, this);
  1865.         }
  1866.        
  1867.         if (ds) {
  1868.             ds.on('activenodechange', this.onStoreActiveNodeChange, this);
  1869.             ds.on('expandnode', this.onStoreExpandNode, this);
  1870.             ds.on('collapsenode', this.onStoreCollapseNode, this);
  1871.         }
  1872.        
  1873.     },
  1874.        
  1875.     onStoreActiveNodeChange: function(store, old_rc, new_rc){
  1876.         var parents, i, len, rec, items = [], ts = this.templates;
  1877.        
  1878.         if (new_rc) {
  1879.             parents = this.ds.getNodeAncestors(new_rc), parents.reverse();
  1880.             parents.push(new_rc);
  1881.            
  1882.             for (i = 0, len = parents.length; i < len; i++) {
  1883.                 rec = parents[i];
  1884.                 items.push(ts.brd_item.apply({
  1885.                     id: rec.id,
  1886.                     title: this.grid.i18n.breadcrumbs_tip,
  1887.                     caption: rec.get(this.cm.getDataIndex(this.cm.getIndexById(this.grid.master_column_id)))
  1888.                 }));
  1889.             }
  1890.            
  1891.             this.breadcrumbs_el.update(this.grid.i18n.path_separator +
  1892.             ts.brd_item.apply({
  1893.                 id: '',
  1894.                 title: this.grid.i18n.breadcrumbs_root_tip,
  1895.                 caption: this.grid.root_title
  1896.             }) +
  1897.             this.grid.i18n.path_separator +
  1898.             items.join(this.grid.i18n.path_separator));
  1899.         } else {
  1900.             this.setRootBreadcrumbs();
  1901.         }
  1902.     },
  1903.    
  1904.     setRootBreadcrumbs: function(){
  1905.         var ts = this.templates;
  1906.         this.breadcrumbs_el.update(this.grid.i18n.path_separator +
  1907.         ts.brd_item.apply({
  1908.             id: '',
  1909.             title: this.grid.i18n.breadcrumbs_root_tip,
  1910.             caption: this.grid.root_title
  1911.         }));
  1912.     },
  1913.    
  1914.     onLoad: function(store, records, options){
  1915.         var id = store.getLoadedNodeIdFromOptions(options);
  1916.         if (id === null) {
  1917.             Ext.ux.maximgb.treegrid.GridView.superclass.onLoad.call(this, store, records, options);
  1918.         }
  1919.     },
  1920.    
  1921.     onStoreExpandNode: function(store, rc){
  1922.         this.expandRow(rc);
  1923.     },
  1924.    
  1925.     onStoreCollapseNode: function(store, rc){
  1926.         this.collapseRow(rc);
  1927.     }
  1928. });
  1929.  
  1930. Ext.ux.maximgb.treegrid.GridPanel = Ext.extend(Ext.grid.GridPanel, {
  1931.    
  1932.     deferRowRender: false,
  1933.    
  1934.     /**
  1935.      * @cfg {String|Integer} master_column_id Master column id. Master column cells are nested.
  1936.      * Master column cell values are used to build breadcrumbs.
  1937.      */
  1938.     master_column_id: 0,
  1939.    
  1940.     /**
  1941.      * @cfg {String} Root node title.
  1942.      */
  1943.     root_title: null,
  1944.    
  1945.     /**
  1946.      * @cfg {Object} i18n I18N text strings.
  1947.      */
  1948.     i18n: null,
  1949.    
  1950.     // Private
  1951.     initComponent: function() {
  1952.        
  1953.         Ext.ux.maximgb.treegrid.GridPanel.superclass.initComponent.call(this);
  1954.        
  1955.         Ext.applyIf(this.i18n, Ext.ux.maximgb.treegrid.GridPanel.prototype.i18n);
  1956.        
  1957.         if (!this.root_title) {
  1958.             this.root_title = this.title || this.i18n.root_title;
  1959.         }
  1960.        
  1961.         this.getSelectionModel().on('selectionchange', this.onTreeGridSelectionChange, this);
  1962.     },
  1963.    
  1964.     expandAllNodes: function(){
  1965.    
  1966.         var store = this.getStore();
  1967.        
  1968.         store.data.each(function(record){
  1969.             if (!store.isLeafNode(record) && store.isLoadedNode(record)) {
  1970.                 store.expandNode(record);
  1971.             }
  1972.         });
  1973.        
  1974.     },
  1975.    
  1976.     collapseAllNodes: function(){
  1977.    
  1978.         var store = this.getStore();
  1979.        
  1980.         store.data.each(function(record){
  1981.             if (!store.isLeafNode(record) && store.isLoadedNode(record)) {
  1982.                 store.collapseNode(record);
  1983.             }
  1984.         });
  1985.        
  1986.     },
  1987.    
  1988.     /**
  1989.      * Returns view instance.
  1990.      *
  1991.      * @access private
  1992.      * @return {GridView}
  1993.      */
  1994.     getView: function(){
  1995.         if (!this.view) {
  1996.             this.view = new Ext.ux.maximgb.treegrid.GridView(this.viewConfig);
  1997.         }
  1998.         return this.view;
  1999.     },
  2000.    
  2001.     /**
  2002.      * @access private
  2003.      */
  2004.     onClick: function(e){
  2005.    
  2006.         var target = e.getTarget(),
  2007.             view = this.getView(),
  2008.             row = view.findRowIndex(target),
  2009.             store = this.getStore(),
  2010.             sm = this.getSelectionModel(),
  2011.             record,
  2012.             record_id,
  2013.             do_default = true
  2014.         ;
  2015.        
  2016.         // Row click
  2017.         if (row !== false) {
  2018.        
  2019.             if (Ext.fly(target).hasClass('ux-maximgb-treegrid-elbow-active')) {
  2020.                 record = store.getAt(row);
  2021.                 if (store.isExpandedNode(record)) {
  2022.                     store.collapseNode(record);
  2023.                 } else {
  2024.                     store.expandNode(record);
  2025.                 }
  2026.                 do_default = false;
  2027.             }
  2028.            
  2029.         } // Breadcrumb click
  2030.  else if (Ext.fly(target).hasClass('ux-maximgb-treegrid-brditem')) {
  2031.             record_id = Ext.id(target);
  2032.             record_id = record_id.substr(record_id.lastIndexOf('-') + 1);
  2033.             if (record_id != '') {
  2034.                 record = store.getById(record_id);
  2035.                 row = store.indexOf(record);
  2036.                
  2037.                 if (e.hasModifier()) {
  2038.                     if (store.isExpandedNode(record)) {
  2039.                         store.collapseNode(record);
  2040.                     } else {
  2041.                         store.expandNode(record);
  2042.                     }
  2043.                 } else if (sm.isSelected && !sm.isSelected(row)) {
  2044.                     sm.selectRow(row);
  2045.                 }
  2046.             } else {
  2047.                 sm.clearSelections();
  2048.             }
  2049.             e.preventDefault();
  2050.         }
  2051.        
  2052.         if (do_default) {
  2053.             Ext.ux.maximgb.treegrid.GridPanel.superclass.onClick.call(this, e);
  2054.         }
  2055.     },
  2056.    
  2057.     /**
  2058.      * @access private
  2059.      */
  2060.     onMouseDown: function(e){
  2061.         var target = e.getTarget();
  2062.        
  2063.         if (!Ext.fly(target).hasClass('ux-maximgb-treegrid-elbow-active')) {
  2064.             Ext.ux.maximgb.treegrid.GridPanel.superclass.onMouseDown.call(this, e);
  2065.         }
  2066.     },
  2067.    
  2068.     /**
  2069.      * @access private
  2070.      */
  2071.     onDblClick: function(e){
  2072.    
  2073.         var target = e.getTarget(),
  2074.             view = this.getView(),
  2075.             row = view.findRowIndex(target),
  2076.             store = this.getStore(),
  2077.             sm = this.getSelectionModel(),
  2078.             record,
  2079.             record_id
  2080.         ;
  2081.        
  2082.         // Breadcrumbs select + expand/collapse
  2083.         if (!row && Ext.fly(target).hasClass('ux-maximgb-treegrid-brditem')) {
  2084.             record_id = Ext.id(target);
  2085.             record_id = record_id.substr(record_id.lastIndexOf('-') + 1);
  2086.             if (record_id != '') {
  2087.                 record = store.getById(record_id);
  2088.                 row = store.indexOf(record);
  2089.                
  2090.                 if (store.isExpandedNode(record)) {
  2091.                     store.collapseNode(record);
  2092.                 } else {
  2093.                     store.expandNode(record);
  2094.                 }
  2095.                
  2096.                 if (sm.isSelected && !sm.isSelected(row)) {
  2097.                     sm.selectRow(row);
  2098.                 }
  2099.             } else {
  2100.                 sm.clearSelections();
  2101.             }
  2102.         } else if (Ext.fly(target).hasClass('x-grid3-col-' + this.master_column_id)) {
  2103.        
  2104.             record = store.getAt(row);
  2105.             if (store.isExpandedNode(record)) {
  2106.                 store.collapseNode(record);
  2107.             } else {
  2108.                 store.expandNode(record);
  2109.             }
  2110.            
  2111.         }
  2112.        
  2113.        
  2114.        
  2115.         Ext.ux.maximgb.treegrid.GridPanel.superclass.onDblClick.call(this, e);
  2116.     },
  2117.    
  2118.     /**
  2119.      * @access private
  2120.      */
  2121.     onTreeGridSelectionChange: function(sm, selection){
  2122.         var record;
  2123.         // Row selection model
  2124.         if (sm.getSelected) {
  2125.             record = sm.getSelected();
  2126.             this.getStore().setActiveNode(record);
  2127.         } // Cell selection model
  2128.  else if (Ext.type(selection) == 'array' && selection.length > 0) {
  2129.             record = store.getAt(selection[0])
  2130.             this.getStore().setActiveNode(record);
  2131.         } else {  throw "Unknown selection model applyed to the grid."; }
  2132.     }
  2133. });
  2134.  
  2135. Ext.ux.maximgb.treegrid.GridPanel.prototype.i18n = {
  2136.     path_separator: ' / ',
  2137.     root_title: '[root]',
  2138.     breadcrumbs_tip: 'Click to select node, CTRL+Click to expand or collapse node, Double click to select and expand or collapse node.',
  2139.     breadcrumbs_root_tip: 'Click to select the top level node.'
  2140. }
  2141.  
  2142. /**
  2143.  * Paging toolbar for work this AbstractTreeStore.
  2144.  */
  2145. Ext.ux.maximgb.treegrid.PagingToolbar = Ext.extend(Ext.PagingToolbar, {
  2146.     onRender: function(ct, position){
  2147.         Ext.ux.maximgb.treegrid.PagingToolbar.superclass.onRender.call(this, ct, position);
  2148.         this.updateUI();
  2149.     },
  2150.    
  2151.     getPageData: function(){
  2152.         var total = 0, cursor = 0;
  2153.         if (this.store) {
  2154.             cursor = this.store.getActiveNodePageOffset();
  2155.             total = this.store.getActiveNodeTotalCount();
  2156.         }
  2157.         return {
  2158.             total: total,
  2159.             activePage: Math.ceil((cursor + this.pageSize) / this.pageSize),
  2160.             pages: total < this.pageSize ? 1 : Math.ceil(total / this.pageSize)
  2161.         };
  2162.     },
  2163.    
  2164.     updateInfo: function(){
  2165.         var count = 0, cursor = 0, total = 0, msg;
  2166.         if (this.displayEl) {
  2167.             if (this.store) {
  2168.                 cursor = this.store.getActiveNodePageOffset();
  2169.                 count = this.store.getActiveNodeCount();
  2170.                 total = this.store.getActiveNodeTotalCount();
  2171.             }
  2172.             msg = count == 0 ? this.emptyMsg : String.format(this.displayMsg, cursor + 1, cursor + count, total);
  2173.             this.displayEl.update(msg);
  2174.         }
  2175.     },
  2176.    
  2177.     updateUI: function(){
  2178.         var d = this.getPageData(), ap = d.activePage, ps = d.pages;
  2179.        
  2180.         this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
  2181.         this.field.dom.value = ap;
  2182.         this.first.setDisabled(ap == 1);
  2183.         this.prev.setDisabled(ap == 1);
  2184.         this.next.setDisabled(ap == ps);
  2185.         this.last.setDisabled(ap == ps);
  2186.         this.loading.enable();
  2187.         this.updateInfo();
  2188.     },
  2189.    
  2190.     unbind: function(store){
  2191.         Ext.ux.maximgb.treegrid.PagingToolbar.superclass.unbind.call(this, store);
  2192.         store.un('activenodechange', this.onStoreActiveNodeChange, this);
  2193.     },
  2194.    
  2195.     bind: function(store){
  2196.         Ext.ux.maximgb.treegrid.PagingToolbar.superclass.bind.call(this, store);
  2197.         store.on('activenodechange', this.onStoreActiveNodeChange, this);
  2198.     },
  2199.    
  2200.     beforeLoad: function(store, options){
  2201.         Ext.ux.maximgb.treegrid.PagingToolbar.superclass.beforeLoad.call(this, store, options);
  2202.         if (options && options.params) {
  2203.             if (options.params[this.paramNames.start] === undefined) {
  2204.                 options.params[this.paramNames.start] = 0;
  2205.             }
  2206.             if (options.params[this.paramNames.limit] === undefined) {
  2207.                 options.params[this.paramNames.limit] = this.pageSize;
  2208.             }
  2209.         }
  2210.     },
  2211.    
  2212.     onClick: function(which){
  2213.         var store = this.store, cursor = store ? store.getActiveNodePageOffset() : 0, total = store ? store.getActiveNodeTotalCount() : 0;
  2214.        
  2215.         switch (which) {
  2216.             case "first":
  2217.                 this.doLoad(0);
  2218.                 break;
  2219.             case "prev":
  2220.                 this.doLoad(Math.max(0, cursor - this.pageSize));
  2221.                 break;
  2222.             case "next":
  2223.                 this.doLoad(cursor + this.pageSize);
  2224.                 break;
  2225.             case "last":
  2226.                 var extra = total % this.pageSize;
  2227.                 var lastStart = extra ? (total - extra) : total - this.pageSize;
  2228.                 this.doLoad(lastStart);
  2229.                 break;
  2230.             case "refresh":
  2231.                 this.doLoad(cursor);
  2232.                 break;
  2233.         }
  2234.     },
  2235.    
  2236.     onStoreActiveNodeChange: function(store, old_rec, new_rec){
  2237.         if (this.rendered) {
  2238.             this.updateUI();
  2239.         }
  2240.     }
  2241. });
  2242.  
  2243. Ext.override(Ext.ux.maximgb.treegrid.GridPanel, {
  2244.     /*
  2245.      EditorGridPanel makes some assumptions about the dom structure.
  2246.      We need to override this method as the dom structure is not exactly as expected
  2247.      */
  2248.     startEditing: function(row, col){
  2249.         this.stopEditing();
  2250.         if (this.colModel.isCellEditable(col, row)) {
  2251.             this.view.ensureVisible(row, col, true);
  2252.             var r = this.store.getAt(row);
  2253.             var field = this.colModel.getDataIndex(col);
  2254.             var e = {
  2255.                 grid: this,
  2256.                 record: r,
  2257.                 field: field,
  2258.                 value: r.data[field],
  2259.                 row: row,
  2260.                 column: col,
  2261.                 cancel: false
  2262.             };
  2263.             if (this.fireEvent("beforeedit", e) !== false && !e.cancel) {
  2264.                 this.editing = true;
  2265.                 var ed = this.colModel.getCellEditor(col, row);
  2266.                 if (!ed.rendered) {
  2267.                     ed.render(this.view.getEditorParent(ed));
  2268.                 }
  2269.                 (function(){ // complex but required for focus issues in safari, ie and opera
  2270.                     ed.row = row;
  2271.                     ed.col = col;
  2272.                     ed.record = r;
  2273.                     ed.on("complete", this.onEditComplete, this, {
  2274.                         single: true
  2275.                     });
  2276.                     ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
  2277.                     this.activeEditor = ed;
  2278.                     var v = this.preEditValue(r, field);
  2279.                     /* gd */
  2280.                     var dom = this.view.getCell(row, col).firstChild;
  2281.                     var masterColumnIndex = this.colModel.findColumnIndex(this.master_column_id);
  2282.                     if (col == masterColumnIndex) {
  2283.                         var el = Ext.get(dom);
  2284.                         dom = el.next();
  2285.                     }
  2286.                     ed.startEdit(dom, v);
  2287.                     /* end gd */
  2288.                 }).defer(50, this);
  2289.             }
  2290.         }
  2291.     },
  2292.     onTreeGridSelectionChange: function(sm, selection){
  2293.         if (!selection && !sm.getSelected) {
  2294.             this.getStore().setActiveNode(null);
  2295.             return;
  2296.         }
  2297.         var record;
  2298.         // Row selection model
  2299.         if (sm.getSelected) {
  2300.             record = sm.getSelected();
  2301.             this.getStore().setActiveNode(record);
  2302.         } // Cell selection model
  2303.  else {
  2304.             if (selection.cell) {
  2305.                 record = this.getStore().getAt(selection.cell[0]);
  2306.                 this.getStore().setActiveNode(record);
  2307.             }
  2308.         }
  2309.     },
  2310.     onRender: function(){
  2311.         Ext.ux.maximgb.treegrid.GridPanel.superclass.onRender.apply(this, arguments);
  2312.         var store = this.store;
  2313.         if (this.enableDragDrop != false) {
  2314.             var canDrop = function(draggedRecord, overRecord){
  2315.                 if (Ext.isEmpty(overRecord)) return true;
  2316.                 if (store.getNodeParent(draggedRecord) === overRecord) { return false; }
  2317.                 if (overRecord === draggedRecord) { return false; }
  2318.                 if (overRecord.isNew) { return false; }
  2319.                
  2320.                 var index = store.getNodeAncestors(overRecord).indexOf(draggedRecord);
  2321.                
  2322.                 return index < 0;
  2323.             };
  2324.            
  2325.             var ddGroupId = this.id + '-dd-group';
  2326.             var dragZone = new Ext.grid.GridDragZone(this, {
  2327.                 ddGroup: ddGroupId
  2328.             });
  2329.             var dropZone = new Ext.dd.DropZone(this.getView().scroller, {
  2330.                 ddGroup: ddGroupId,
  2331.                 notifyOver: function(dd, evt, data){
  2332.                     var cls = this.dropNotAllowed;
  2333.                    
  2334.                     var draggedRecord = dd.dragData.selections[0];
  2335.                    
  2336.                     var target = evt.getTarget();
  2337.                     var rowIndex = this.getView().findRowIndex(target);
  2338.                    
  2339.                     var overRecord = this.getStore().getAt(rowIndex);
  2340.                    
  2341.                     if (canDrop(draggedRecord, overRecord)) {
  2342.                         cls = Ext.dd.DropZone.prototype.dropAllowed;
  2343.                     }
  2344.                    
  2345.                     return cls;
  2346.                 }
  2347. .createDelegate(this)               ,
  2348.                 notifyDrop: function(dd, evt, data){
  2349.                     var draggedRecord = dd.dragData.selections[0];
  2350.                    
  2351.                     var target = evt.getTarget();
  2352.                     var rowIndex = this.getView().findRowIndex(target);
  2353.                    
  2354.                     var overRecord = this.getStore().getAt(rowIndex);
  2355.                    
  2356.                     var candrop = canDrop(draggedRecord, overRecord);
  2357.                    
  2358.                     if (candrop) {
  2359.                         if (overRecord) {
  2360.                        
  2361.                             var fn = function(){
  2362.                                 var store = this.getStore();
  2363.                                
  2364.                                 var parentId = overRecord.get('oid');
  2365.                                 draggedRecord.set(store.parent_id_field_name, parentId);
  2366.                                
  2367.                                 store.applyTreeSort();
  2368.                                
  2369.                                 this.getSelectionModel().deselectRange();
  2370.                                 this.getSelectionModel().selectRecords([draggedRecord], false);
  2371.                                
  2372.                                 this.getView().refresh(true);
  2373.                                
  2374.                                
  2375.                             }
  2376. .createDelegate(this);
  2377.                            
  2378.                             var expanded = this.store.isExpandedNode(overRecord);
  2379.                             if (!expanded) {
  2380.                                 this.expandAndApply(overRecord, fn);
  2381.                             } else {
  2382.                                 fn();
  2383.                             }
  2384.                         } else {
  2385.                             var store = this.getStore();
  2386.                            
  2387.                             draggedRecord.set(store.parent_id_field_name, null);
  2388.                            
  2389.                             store.applyTreeSort();
  2390.                            
  2391.                             this.getSelectionModel().deselectRange();
  2392.                             this.getSelectionModel().selectRecords([draggedRecord], false);
  2393.                            
  2394.                             this.getView().refresh(true);
  2395.                            
  2396.                         }
  2397.                         return true;
  2398.                     }
  2399.                 }
  2400. .createDelegate(this)
  2401.             });
  2402.            
  2403.             this.dropZone = dropZone;
  2404.         }
  2405.     },
  2406.     expandAndApply: function(anode, fn){
  2407.         if (!anode) {
  2408.             fn();
  2409.             return;
  2410.         }
  2411.        
  2412.         var store = this.getStore();
  2413.        
  2414.         var storeExpandNodeCallback = store.expandNodeCallback;
  2415.        
  2416.         store.expandNodeCallback = function(r, options, success){
  2417.             storeExpandNodeCallback.apply(store, arguments);
  2418.             fn();
  2419.         }
  2420. .createDelegate(this);
  2421.         store.expandNode(anode);
  2422.         store.setActiveNode(anode);
  2423.        
  2424.         store.expandNodeCallback = storeExpandNodeCallback;
  2425.     }
  2426. });
  2427.  
  2428. Ext.reg('ux-maximgb-treegrid', Ext.ux.maximgb.treegrid.GridPanel);
  2429. Ext.reg('ux-maximgb-paging', Ext.ux.maximgb.treegrid.PagingToolbar);
  2430.  
  2431.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement